#ifndef FILE_HPP_
#define FILE_HPP_

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>

#include "Logger.hpp"

class File {
public:
	enum Mode {
		MODE_READ,
		MODE_WRITE,
		MODE_RW
	};

	Mode mode;
	char path[20];
	unsigned int size, offset, mSize, cSize;
	int fd;
	char *mPtr;	//pointer to mapped data
	char *cPtr;  	//pointer to current char
	bool isOpened, isMapped;

	File() {
		init();
	}

	void setPath(char *p) {
		init();
		strncpy(path, p ,20);
	}

	void Open(Mode m) {
		init();

		if (NULL == path) {
			Logger::getInstance().log(Logger::ERROR, "Failed to open file: path is not specified.\n");
			exit(1);
		}

		mode = m;
		if (MODE_READ == mode) {
			fd = open(path, O_RDONLY);
		}
		if (MODE_WRITE == mode) {
			fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);       	
		}
		if (MODE_RW == mode) {
			fd = open(path, O_RDWR|O_CREAT, 0644); 		
		}

		if (-1 == fd) { 
			Logger::getInstance().log(Logger::ERROR, "Failed to open file *%s*.\n", path);		
			exit(1);
		}

		struct stat fileStatus;
		if (fstat(fd, &fileStatus) < 0) {
			Logger::getInstance().log(Logger::ERROR, "Failed to get file status of file *%s*.\n", path);
			exit(1);
		}
		size = fileStatus.st_size;

		isOpened = 1;
	}

	void Close() {
		if ( ! isOpened) {
			Logger::getInstance().log(Logger::ERROR, "Failed to close file *%s*: file is not opened.\n", path);
			exit(1);
		}

		if (isMapped) {
			Logger::getInstance().log(Logger::ERROR, "Failed to close file *%s*: file is mapped.\n", path);
			exit(1);
		}

		if (close(fd) != 0) {
			Logger::getInstance().log(Logger::WARNING, "Failed to close file *%s*.\n", path);
		} else {
			isOpened = 0;
		}
	}

	void init() {
		mPtr = NULL;
		cPtr = NULL;
		size = 0;
		offset = 0;
		mSize = 0;
		cSize = 0;
		isOpened = 0;
		isMapped = 0;
		fd = -1;
	}
};

#endif /* FILE_HPP_ */
